#pragma once

#include "Control.h"
#include "Container.h"
#include "winuser.h"

#define LISTBOXEX_STYLE_CHECKBOX		 1
#define LISTBOXEX_STYLE_GRIDLINES	     2
#define LISTBOXEX_STYLE_IMAGES		     4
#define INVALID_ITEM					 -1

//Item Types
#define HTML_TEXT					1
#define NORMAL_TEXT					2
#define SINGLE_LINE_TEXT			3
//end

//Calculate Item height Automatically
#define AUTO	                 0

//Padding between items
#define ITEM_PADDING_TOP			5
#define ITEM_PADDING_BOTTOM			5
#define ITEM_PADDING_LEFT			5
#define ITEM_PADDING_CHECKBOX_LEFT	3
#define ITEM_IMAGE_PADDING_LEFT		5
#define ITEM_IMAGE_PADDING_RIGHT	5
#define ITEM_CHECKBOX_WIDTH			16

//for selection
#define NONE_SELECTED				-1

//Events
#define LISTBOXEX_SELECTIONCHANGED	1
#define LISTBOXEX_LBUTTONDOWN		2
#define LISTBOXEX_RBUTTONDOWN		3
#define HTMLLIST_LBUTTONDBLCLICK	4
#define HTMLLIST_ITEMCHECKED		5

struct  NM_LISTBOXEX
{
	NMHDR hdr;
	int nItemNo;
	wstring sItemText;
	LPARAM lItemData;
	BOOL bChecked;
};

struct  LISTBOXEX_ITEM
{
	LISTBOXEX_ITEM()
	{
		nItemNo				= INVALID_ITEM;
		lItemData			= 0;
		nHeight				= 0;
		nStyle				= NORMAL_TEXT;
		rcItem.SetRectEmpty();
		bChecked			= FALSE;
		bHeightSpecified	= TRUE;
	}

	int			nItemNo;
	int			nHeight;
	int			nStyle;
	wstring		sItemText;
	LPARAM		lItemData;
	CRect		rcItem;
	BOOL		bChecked;
	BOOL		bHeightSpecified;
	UINT		uiImage;
};

/** 
 * Listbox without column support,only list mode supported in current version
 */

class GUI_API CListBoxEx : 	public CControl
{
public:
	CListBoxEx(void);
	/**
	*@param[in]  nID		 Specifies the  ID       of the control
	*/
	CListBoxEx(UINT nID);
	/**
	*@param[in]  strCaption  Specifies the  caption  of the control 
	*@param[in]  nID		 Specifies the  ID       of the control
	*/
	CListBoxEx(wstring strCaption,UINT nID);
	/**
	*@param[in]  dwStyle Specifies the  style of the control
	*@li @c SWS_STATIC   static control without any vents
	*@li @c SBS_ACTIVE  
	*@li @c SBS_ROUND
	*@li @c SBS_RECT
	*@param[in]  strCaption  Specifies the  caption  of the control 
	*@param[in]  rc           Specifies the  position of the control
	*@param[in]  nID		 Specifies the  ID       of the control
	*/
	CListBoxEx(DWORD dwStyle, wstring strCaption,const CRect &rc, UINT nID);
	/**
	*@param[in]  dwStyle Specifies the  style of the control
	*@li @c SWS_STATIC   static control without any vents
	*@li @c SBS_ACTIVE  
	*@li @c SBS_ROUND
	*@li @c SBS_RECT
	*@param[in]  strCaption  Specifies the  caption  of the control 
	*@param[in]  x           Specifies the  position of the left side of the control
	*@param[in]  y           Specifies the  position of the top  side of the control
	*@param[in]  cx          Specifies the  position of the width of the control
	*@param[in]  cy          Specifies the  position of the control
	*@param[in]  nID		 Specifies the  ID       of the control
	*/
	CListBoxEx(DWORD dwStyle, wstring strCaption, int x, int y, int cx, int cy, UINT nID);
	virtual ~CListBoxEx(void);

private:
	void Init();

public:

	/** 
	 *@brief Specifies the new text left margin in Pixel
	 *@param  nMargin the new text left margin in Pixel
	 *@return No return value
	 */
	inline void SetTextLeftMargin(int nMargin)
	{
		m_nTextLeftMargin = nMargin;
	}

	/** 
	*@brief Get the text left margin 
	*@return the text left margin in Pixel
	*/
	inline int GetTextLeftMargin()
	{
		return m_nTextLeftMargin;
	}

	inline int GetPos()
	{
		return m_nPos;
	}

	void SetPos(int nPos);

	inline void SetSelItem(int nSelItem)
	{
		m_nSelectedItem = nSelItem;
	}

	inline int	GetItemCount()
	{
		return m_listItems.size();
	}

	inline void  SetImageListIcon(CImageList *pImageList)
	{
		m_pImgLstIcon = pImageList;
	}

	inline  CImageList* SetImageListIcon()
	{
		return m_pImgLstIcon;
	}

	inline void SetImageListCheck(CImageList *pImageList)
	{
		m_ImgLstCheck = pImageList;
	}

	inline CImageList* SetImageListCheck()
	{
		return m_ImgLstCheck;
	}

	inline int GetPageCap()
	{
		return m_nPageCap;
	}

	inline int GetTotalPage()
	{
		return m_nTotalPages;
	}

	inline int GetCurPage()
	{
		return m_nCurPage;
	}

	inline void SetCurPage(int nCurPage)
	{
		m_nCurPage = nCurPage;

		if(nCurPage > m_nTotalPages)
		{
			m_nCurPage = m_nTotalPages;
		}

		if(0 > nCurPage)
		{
			m_nCurPage = 0;
		}

		SetPos(m_nCurPage*GetPageCap());
	}

	inline int GetPageByPos(int nPos)
	{
		if(0 >= nPos)
		{
			return 0;
		}

		if(m_nPageCap == 0)
		{
			return 0;
		}

		return nPos/GetPageCap();
	}

	inline void ShowNextPage()
	{
		SetCurPage(m_nCurPage++);
	}

	inline void ShowPrevPage()
	{
		SetCurPage(m_nCurPage--);
	}

	inline void LineUp()
	{
		SetPos(m_nPos - 1);
	}

	inline void LineDown()
	{
		SetPos(m_nPos + 1);
	}

	inline void SetSelItemBmp(HBITMAP hBmp)
	{
		if(m_hSelBackgnd)
		{
			DeleteObject(m_hSelBackgnd);
		}

		m_hSelBackgnd = hBmp;
	}
	
	inline void SetLineStartClr(COLORREF clrLineStart)
	{
		m_clrLineStart = clrLineStart;
	}

	inline void SetLineEndClr(COLORREF clrLineEnd)
	{
		m_clrLineEnd = clrLineEnd;
	}

public:
		inline void SetInternalData(int nPos, LISTBOXEX_ITEM *pData)
		{
			m_mapItems[nPos] = pData;
		}

		void SendCheckStateChangedNotification(int nPos);
		void SendSelectionChangeNotification(int nPos);
		virtual void DrawItem(CDC *pDC,CRect rcItem, LISTBOXEX_ITEM *pItem, BOOL bSelected);
		void SetImage(int nPos,UINT uiImage);
		UINT GetImage(int nPos);
		void ReArrangeWholeLayout();
		void ReArrangeItems();
		BOOL DeleteItem(int nPos);
		void SetItemText(int nPos,wstring sItemText,BOOL bCalculateHeight = FALSE);
		BOOL GetItemCheck(int nPos);
		void SetItemCheck(int nPos,BOOL bChecked = TRUE);
		void EnsureVisible(int nPos);
		DWORD GetExtendedStyle();
		void SetExtendedStyle(DWORD dwExStyle);
		wstring GetItemText(int nPos);
		int GetSelectedItem();
		void SetItemData(int nPos,LPARAM lItemData);
		LPARAM GetItemData(int nPos);
		void DeleteAllItems();
		int InsertItem(wstring sText,UINT uiImage,int nStyle = SINGLE_LINE_TEXT,int nHeight = 30 /*AUTO*/);

protected:
	void  CalPage();
	void  DrawLine(CDC* pDc,CPoint ptStart,CPoint ptEnd);
	CRect GetItemRect(int nPos);

protected:
		HBITMAP m_hSelBackgnd;

		LISTBOXEX_ITEM * GetInternalData(int nPos);
		list<LISTBOXEX_ITEM*> m_listItems; 
		map<const int,LISTBOXEX_ITEM*>m_mapItems;

		int m_nTotalItems;
		int m_nItemHeight;
		int m_nPageCap;
		int m_nTotalPages;
		int m_nCurPage;
		int m_nPos;
		int m_nTextLeftMargin;
		int m_nListHeight;
		int m_nWndWidth;
		int m_nWndHeight;
		int m_nSelectedItem;
		DWORD m_dwExtendedStyles;

		COLORREF m_clrLineStart;
		COLORREF m_clrLineEnd;

		CImageList *m_ImgLstCheck;
		CImageList *m_pImgLstIcon;

protected:
	virtual void Paint(CDC* pDC);

public:
	virtual void Click(DWORD dwClick, POINT pt);

};
